package generate;

//by Andrew Leach
	
import java.util.*;
import java.io.*;

public class generator {
	static ArrayList<LineSegment> linesegs = new ArrayList<LineSegment>();
	static Random rdm = new Random();
	//determines location to print text file
	static String filelocation = "/home/ableach/sketchbook/networkdraw/GSS/generated1.txt";
	//segnum is the number of line segments, it is also
	//the horizontal and vertical grid length
	static int segnum = 100;
	
	public static void main(String args[]){
		//create first line segment
		linesegs.add(new LineSegment("s0",(double)rdm.nextInt(segnum),(double)rdm.nextInt(segnum),
				(double)rdm.nextInt(segnum),(double)rdm.nextInt(segnum)));
		//continue until fully populated
		for(int i = 1;linesegs.size()!=segnum; i++){
			Point pointa = chooseFirstPt();
			Point pointb = chooseSecondPt(pointa);
			if(isLegal(pointa, pointb)){
				linesegs.add(new LineSegment(("s"+Integer.toString(i)),
						pointa.getX(), pointa.getY(), pointb.getX(), pointb.getY()));
			}	
		}
		//this is for testing only!!
		for(int r = 0; r<linesegs.size(); r++){
			linesegs.get(r).printSegment();
		}
		//to print the line segments to a text file
		try{
			
			FileWriter filewrite = new FileWriter(filelocation);
			BufferedWriter fileout = new BufferedWriter(filewrite);
			for(int i = 0; i < linesegs.size(); i++){
				LineSegment templine = linesegs.get(i);
				fileout.write((int)templine.getX1()+" "+
						(int)templine.getY1()+" "+ (int)templine.getX2()+" "+(int)templine.getY2());
				fileout.newLine();
			}
			fileout.close();
		}
		catch (Exception e){
            System.err.println("Error: " + e.getMessage());
        }		
	}//end main
	
	//returns true if a point is greater than a line segment
	public static boolean greaterThanLine(double x, double y, LineSegment seg){
		//handle normal line
		if(seg.isNotVertical()){
			if(seg.yValue(x)>y){
				return false;
			}
		}
		//handle vertical line
		else{
			if(seg.getX1()>x){
				return false;
			}
		}
		return true;
	}
	
	//returns true if a point is greater than a line segment
	public static boolean lessThanLine(double x, double y, LineSegment seg){
		//handle normal line
		if(seg.isNotVertical()){
			if(seg.yValue(x)<y){
				return false;
			}
		}
		//handle vertical line
		else{
			if(seg.getX1()<x){
				return false;
			}
		}
		return true;
	}
	
	//returns the first endpoint of a new line segment
	public static Point chooseFirstPt(){
		int sindex = rdm.nextInt(linesegs.size());		
		LineSegment seg = linesegs.get(sindex);
		double x = (double)rdm.nextInt(segnum);
		double y = (double)rdm.nextInt(segnum);
		//handle normal line
		if(seg.isNotVertical()){
			if(seg.yValue(x)==y){
				return chooseFirstPt();
			}
			else{
				Point point = new Point(x,y,seg);
				return point;
			}
		}
		//handle vertical line
		else{
			if(seg.getX1()==x){
				return chooseFirstPt();
			}
			else{
				Point point = new Point(x,y,seg);
				return point;
			}
		}
	}
	
	//finds y value for a line at a given x. Needed to avoid creating
	//new unnecessary line segments in method chooseSecondPt()
	public static double yValue(double x, double X1, double Y1, double X2, double Y2){
		if(X1!=X2){
			return (Y2-Y1)*x/(X2-X1)+Y1-(X1*(Y2-Y1)/(X2-X1)); 
		}
		else{
			return 0;
		}
      }
	
	//define greaterThanLine() method for points, same reasoning as above
	public static boolean greaterThan(double x, double y, double X1, double Y1, double X2, double Y2){
		//handles normal line 
		if(X1!=X2){
			 if(((Y2-Y1)*x/(X2-X1)+Y1-(X1*(Y2-Y1)/(X2-X1)))>y){
				 return false;
			 }
		}
		//handles vertical line
		else{
			if(X1 > x){
				return false;
			}
		}
		return true;
      }
	
	//define lessThanLine() method for points, same reasoning as above
	public static boolean lessThan(double x, double y, double X1, double Y1, double X2, double Y2){
		//handles normal line 
		if(X1!=X2){
			 if(((Y2-Y1)*x/(X2-X1)+Y1-(X1*(Y2-Y1)/(X2-X1)))<y){
				 return false;
			 }
		}
		//handles vertical line
		else{
			if(X1 < x){
				return false;
			}
		}
		return true;
      }
	
	
	//choose second point of a new line segment in a way such that it must intersect atleast
	// one other line segment
	public static Point chooseSecondPt(Point firstpt){
		LineSegment seg = firstpt.getSeg();
		ArrayList<Point> candidates = new ArrayList<Point>();
		//sets doubles for ease of use, ordered by least x
		double X1,Y1,X2,Y2;
		if(seg.getX1()< seg.getX2()){
			X1 = seg.getX1();
			Y1 = seg.getY1();
			X2 = seg.getX2();
			Y2 = seg.getY2();			
		}
		else{
			X2 = seg.getX1();
			Y2 = seg.getY1();
			X1 = seg.getX2();
			Y1 = seg.getY2();
		}
		
		//handles the case where the segment is not vertical
		if(seg.isNotVertical()){
			//here there are three cases, the first point is to the left of endpoints, 
			//between endpoints, or to the right of endpoints
			
			//case where first point is to the left of the segment
			if(firstpt.getX()<=X1){
				
				//handles the case where the point is greater than the seg
				if(greaterThanLine(firstpt.getX(), firstpt.getY(), seg)){
					for(int i = 0; i < segnum; i++){
						for(int j = 0; j < segnum; j++){
							//makes sure that the point is in such a region
							//that would guarantee intersection
							if(lessThanLine((double)i, (double)j, seg)&&
									greaterThan((double)i, (double)j, firstpt.getX(), firstpt.getY(), X1, Y1)&&
									lessThan((double)i, (double)j, firstpt.getX(), firstpt.getY(), X2, Y2)){
								Point testpt = new Point((double)i, (double)j, seg);
								candidates.add(testpt);
							}
						}
					}
				}
			
				//handles the case where the point is less than the seg.
				else{
					for(int i = 0; i < segnum; i++){
						for(int j = 0; j < segnum; j++){						
							//makes sure that the point is in such a region
							//that would guarantee intersection
							if(greaterThanLine((double)i, (double)j, seg)&&
									lessThan((double)i, (double)j, firstpt.getX(), firstpt.getY(), X1, Y1)&&
									greaterThan((double)i, (double)j, firstpt.getX(), firstpt.getY(), X2, Y2)){
								Point testpt = new Point((double)i, (double)j, seg);
								candidates.add(testpt);
							}
						}
					}			
				}				
			}
			
			//case where first point is to the right of the segment
			else if(firstpt.getX()>Math.max(seg.getX1(),seg.getX2())){
				
				//handles the case where the point is greater than the seg
				if(greaterThanLine(firstpt.getX(), firstpt.getY(), seg)){
					for(int i = 0; i < segnum; i++){
						for(int j = 0; j < segnum; j++){
							//makes sure that the point is in such a region
							//that would guarantee intersection
							if(lessThanLine((double)i, (double)j, seg)&&
									lessThan((double)i, (double)j, firstpt.getX(), firstpt.getY(), X1, Y1)&&
									greaterThan((double)i, (double)j, firstpt.getX(), firstpt.getY(), X2, Y2)){
								Point testpt = new Point((double)i, (double)j, seg);
								candidates.add(testpt);
							}
						}
					}
				}
			
				//handles the case where the point is less than the seg.
				else{
					for(int i = 0; i < segnum; i++){
						for(int j = 0; j < segnum; j++){						
							//makes sure that the point is in such a region
							//that would guarantee intersection
							if(greaterThanLine((double)i, (double)j, seg)&&
									greaterThan((double)i, (double)j, firstpt.getX(), firstpt.getY(), X1, Y1)&&
									lessThan((double)i, (double)j, firstpt.getX(), firstpt.getY(), X2, Y2)){
								Point testpt = new Point((double)i, (double)j, seg);
								candidates.add(testpt);
							}
						}
					}			
				}
			}
			
			//case where first point is in between endpoints of the segment
			else{			
				//handles the case where the point is greater than the seg
				if(greaterThanLine(firstpt.getX(), firstpt.getY(), seg)){
					for(int i = 0; i < segnum; i++){
						for(int j = 0; j < segnum; j++){
							//makes sure that the point is in such a region
							//that would guarantee intersection
							if(lessThanLine((double)i, (double)j, seg)&&
									lessThan((double)i, (double)j, firstpt.getX(), firstpt.getY(), seg.getX1(), seg.getY1())&&
									lessThan((double)i, (double)j, firstpt.getX(), firstpt.getY(), seg.getX2(), seg.getY2())){
								Point testpt = new Point((double)i, (double)j, seg);
								candidates.add(testpt);
							}
						}
					}
				}
			
				//handles the case where the point is less than the seg.
				else{
					for(int i = 0; i < segnum; i++){
						for(int j = 0; j < segnum; j++){						
							//makes sure that the point is in such a region
							//that would guarantee intersection
							if(greaterThanLine((double)i, (double)j, seg)&&
									greaterThan((double)i, (double)j, firstpt.getX(), firstpt.getY(), seg.getX1(), seg.getY1())&&
									greaterThan((double)i, (double)j, firstpt.getX(), firstpt.getY(), seg.getX2(), seg.getY2())){
								Point testpt = new Point((double)i, (double)j, seg);
								candidates.add(testpt);
							}
						}
					}			
				}
			}
		}	
		
		//handles the case where the segment is vertical
		else{
			//point is on right of vertical segment
			if(firstpt.getX()>seg.getX1()){
				for(int i = 0; i < segnum; i++){
					for(int j = 0; j < segnum; j++){
						if(lessThanLine((double)i, (double)j, seg)&& 
								lessThan((double)i, (double)j, firstpt.getX(), firstpt.getY(), seg.getX1(), Math.max(seg.getY1(),seg.getY2()))&&
								greaterThan((double)i, (double)j, firstpt.getX(), firstpt.getY(), seg.getX1(), Math.min(seg.getY1(),seg.getY2()))){
							Point testpt = new Point((double)i, (double)j, seg);
							candidates.add(testpt);
						}
					}
				}	
			}
			//point is on left of vertical segment
			else{
				for(int i = 0; i < segnum; i++){
					for(int j = 0; j < segnum; j++){
						if(greaterThanLine((double)i, (double)j, seg)&& 
								lessThan((double)i, (double)j, firstpt.getX(), firstpt.getY(), seg.getX1(), Math.max(seg.getY1(),seg.getY2()))&&
								greaterThan((double)i, (double)j, firstpt.getX(), firstpt.getY(), seg.getX1(), Math.min(seg.getY1(),seg.getY2()))){
							Point testpt = new Point((double)i, (double)j, seg);
							candidates.add(testpt);
						}
					}
				}	
			}
		}	
		System.out.println(candidates.size());//delete this, only for a test!!!
		linesegs.get(linesegs.size()-1).printSegment();//delete this, only for a test!!!
		System.out.println(" first pt " + Double.toString(firstpt.getX()) +" , " + Double.toString(firstpt.getY()));//delete this, only for a test!!!
		System.out.println("chosen segment is "+ firstpt.getSeg().getName());//delete this, only for a test!!!
		int dindex = rdm.nextInt(candidates.size());		
		Point toadd = candidates.get(dindex);
		return toadd;
	}
	
	//test to see if the two points would form a line segment that overlaps another
	public static boolean isLegal(Point pointa, Point pointb){
		for(int i = 0; i < linesegs.size(); i++){
			LineSegment tempseg = linesegs.get(i);
			//if a line has the same slope as the two points and the same roots
			
			//handles case where line is not vertical
			if(pointa.getX()!=pointb.getX()){				
				if((Math.abs(tempseg.slope())==Math.abs((pointb.getY()-pointa.getY())/(pointb.getX()-pointa.getX())))&&
					(tempseg.yValue(pointa.getX())==pointa.getY())){
					//if one of the points is in the interval of the segment
					if(((Math.min(tempseg.getX1(),tempseg.getX2())<=pointa.getX())&&(Math.max(tempseg.getX1(),tempseg.getX2())>=pointa.getX()))||
						((Math.min(tempseg.getX1(),tempseg.getX2())<=pointb.getX())&&(Math.max(tempseg.getX1(),tempseg.getX2())>=pointb.getX()))){
						return false;
					}
				}
			}
			else{
				if(((Math.min(tempseg.getY1(),tempseg.getY2()))<=pointa.getY())&&(Math.max(tempseg.getY1(),tempseg.getY2())>=pointa.getY())||
						((Math.min(tempseg.getY1(),tempseg.getY2())<=pointb.getY())&&(Math.max(tempseg.getY1(),tempseg.getY2())>=pointb.getY()))){
					return false;
				}
						
			}
		}
		return true;
	}
	
}//end class
